iT邦幫忙

2024 iThome 鐵人賽

DAY 12
0
Modern Web

從 0 到 1:30 篇文章帶你玩轉 Electron 與 React系列 第 12

狀態管理:原理及工具介紹

  • 分享至 

  • xImage
  •  

在現代前端應用中,尤其是像 React 這類的單頁應用程式 (SPA),狀態管理至關重要。隨著應用規模的增長,應用中的狀態不僅變得更多樣化,而且需要跨元件甚至跨頁面進行共享。為了解決這些問題,狀態管理 應運而生。


什麼是狀態管理?

狀態是指在某一時刻的資料集合。例如,使用者的登錄資訊、購物車中的商品、表單的輸入值等等。狀態管理就是對這些資料進行有效管理,確保資料能夠正確、同步在不同元件中使用。

狀態管理的核心目標是:

  1. 可預測性:通過統一的方式管理應用狀態,使資料流動可預測。
  2. 可維護性:簡化狀態變更的追蹤,方便調試和故障排查。
  3. 高效性:減少不必要的重渲染,優化性能。

狀態管理的原理

1. 單向資料流

狀態管理通常遵循 單向資料流 的原則,即資料總是從單一的源頭流向消費者。這意味著狀態的變更只能通過預定的途徑來進行,保證了資料的可預測性。

具體過程如下:

  • 狀態 (State):應用中的資料。
  • 操作 (Action):使用者或程序的行為,會引發狀態的變更。
  • 修改器 (Reducer):負責根據操作來修改狀態。
  • 新狀態:狀態改變後,新的狀態會通知元件進行重渲染。

2. 可變與不可變狀態

狀態可以分為可變不可變。不可變狀態的變更並不會直接修改狀態本身,而是返回一個新的狀態副本。這種設計使得狀態變更更容易追蹤和調試。


常見的狀態管理工具

隨著前端框架的發展,出現了許多狀態管理工具,它們各有特點,適用於不同的場景。以下介紹一些常見的工具。

1. Redux

Redux 是 React 應用中最流行的狀態管理工具之一。它採用 單一狀態樹 的模式,所有的狀態都集中在一個全局的 store 中,並且狀態只能通過 action 來觸發 reducer 進行修改。

Redux 原理:

  • Store:全局存放應用狀態的地方。
  • Action:描述狀態變化的事件,通常是一個包含 typepayload 的對象。
  • Reducer:純函式,根據 action 的類型來更新狀態。
  • Dispatch:用來分發 action 的方法。

優點:

  • 可預測性高:單一狀態樹和不可變狀態使得資料流向明確,易於追蹤。
  • 豐富的中間件:Redux 的中間件(如 redux-thunkredux-saga)支持異步操作和複雜的業務邏輯。
  • 社群支持:Redux 擁有強大的社群和豐富的插件,適用於大型應用。

缺點:

  • 樣板程式多:需要撰寫大量的 action 和 reducer,對於小型應用可能顯得繁瑣。

Redux 範例:

import { createStore } from 'redux';

// 定義初始狀態
const initialState = {
  counter: 0,
};

// 定義 reducer 函式
function counterReducer(state = initialState, action) {
  switch (action.type) {
    case 'INCREMENT':
      return { counter: state.counter + 1 };
    case 'DECREMENT':
      return { counter: state.counter - 1 };
    default:
      return state;
  }
}

// 創建 store
const store = createStore(counterReducer);

// 分發 action
store.dispatch({ type: 'INCREMENT' });
console.log(store.getState()); // { counter: 1 }

2. Zustand

Zustand 是一個輕量級、無樣板程式的 React 狀態管理工具。它的設計非常靈活,沒有固定的模式或規範,允許開發者根據具體需求靈活使用。

Zustand 原理:

  • Store:可以通過簡單的函式來創建,狀態和狀態的操作都定義在一個地方。
  • Mutate:允許直接修改狀態,類似 MobX 的可變性。
  • Selector:可以選擇部分狀態進行消費,這樣能提高性能,避免不必要的重渲染。

優點:

  • 簡單且無樣板程式:只需少量程式即可實現狀態管理,非常適合中小型應用。
  • 性能優化:內置選擇器功能可以自動避免不必要的重渲染,確保性能。
  • 靈活性高:不像 Redux 那樣有固定的規範,開發者可以自由選擇最佳實踐。

缺點:

  • 社群相對較小:相比 Redux,Zustand 的社群和資源相對較少,但在快速增長中。

Zustand 範例:

  1. 安裝 Zustand:

    npm install zustand
    
  2. 創建狀態管理:

import create from 'zustand';

// 創建 Zustand store
const useStore = create((set) => ({
  counter: 0,
  increment: () => set((state) => ({ counter: state.counter + 1 })),
  decrement: () => set((state) => ({ counter: state.counter - 1 })),
}));

// 使用 Zustand store
function Counter() {
  const { counter, increment, decrement } = useStore();
  
  return (
    <div>
      <h1>Counter: {counter}</h1>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
}

export default Counter;

在這個範例中,useStore 是 Zustand 創建的 store,set 函式用來修改狀態。元件 Counter 中使用 useStore 來訪問狀態及其變更方法。


3. MobX

MobX 是另一個流行的狀態管理工具,採用的是 響應式編程 模式,與 Redux 的單向資料流不同,MobX 的狀態是可觀察的,並且會自動響應變化。

MobX 原理:

  • Observable:可觀察的狀態,當狀態發生變化時,依賴於此狀態的視圖會自動更新。
  • Action:改變狀態的方法。
  • Reaction:響應狀態變化的邏輯。

優點:

  • 簡單易用:MobX 更加靈活且容易上手,少量的樣板程式即可實現狀態管理。
  • 自動響應:當狀態改變時,視圖會自動更新,減少了手動操作。

缺點:

  • 資料流不如 Redux 明確:由於 MobX 的響應式特性,資料流的追蹤會比較複雜。

MobX 範例:

import { makeAutoObservable } from 'mobx';

class CounterStore {
  counter = 0;

  constructor() {
    makeAutoObservable(this);
  }

  increment() {
    this.counter += 1;
  }

  decrement() {
    this.counter -= 1;
  }
}

const counterStore = new CounterStore();
counterStore.increment();
console.log(counterStore.counter); // 1

4. Context API

React Context API 是 React 內建的狀態管理工具,適合用於中小型應用或需要在應用不同部分共享狀態的場景。相比 Redux 和 MobX,Context API 的設置較簡單,並且可以與 React 的元件樹緊密結合。

Context API 原理:

  • Provider:在元件樹中提供狀態的來源。
  • Consumer:在元件中使用狀態的接收方。

優點:

  • 輕量化:內建於 React,無需額外安裝依賴。
  • 簡單易用:適合中小型應用或共享狀態需求不高的應用。

缺點:

  • 性能問題:當狀態頻繁變化時,會導致所有消費者元件重新渲染。

Context API 範例:

import React, { createContext, useState, useContext } from 'react';

// 創建 Context
const CounterContext = createContext();

export const CounterProvider = ({ children }) => {
  const [counter, setCounter] = useState(0);

  return (
    <CounterContext.Provider value={{ counter, setCounter }}>
      {children}
    </CounterContext.Provider>
  );
};

export const useCounter = () => useContext(CounterContext);

// 使用 Context
function Counter() {
  const { counter, setCounter } = useCounter();

  return (
    <div>
      <h1>Counter: {counter}</h1>
      <button onClick={() => setCounter(counter + 1)}>Increment</button>
      <button onClick={() => setCounter(counter - 1)}>Decrement</button>
    </div>
  );
}

總結

狀態管理是現代前端應用中不可或缺的部分,無論是大型應用還是小型專案,合理的狀態管理能夠幫助提升程式的可讀性和維護性。在這篇文章中,我們介紹了多種狀態管理工具,包括 ReduxZustandMobXReact Context API。讀者可以根據應用的需求選擇合適的工具,在維持性能的同時保持簡潔的程式結構。


上一篇
使用 Node.js 操作本地文件系統
系列文
從 0 到 1:30 篇文章帶你玩轉 Electron 與 React12
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言